# coding=utf-8
import numpy as np
import pandas as pd
import gTdev
import os
from matplotlib import pyplot as plt
from wuniform import wuniform
import json
import asyncio

plt.style.use('default')
currentType = ['DrainI',"SourceI"][1]

def figureDir(path):
    figurePath = os.path.join(path,'figure')
    if not os.path.isdir(figurePath):
        os.mkdir(figurePath)
    return figurePath

def transcurve(path,force=False):
    figpath = os.path.join(figureDir(path),'transCurve.png')
    if os.path.isfile(figpath):
        if not force:
            return figpath
    try:
        ######绘制图像#####
        plt.clf()
        plt.title("Transfer Curve")
        plt.xlabel("GateV(V)")
        plt.ylabel(currentType+"(A)")
        plt.yscale("log")#对数坐标，如果需要线性坐标可以注释掉这一行
        #绘制图像
        ######读取文件并提取曲线#####
        testFiles = gTdev.gtfile(location=path,key="MOS",
                                Y_Axis=currentType,Z_Axis='GateI',absY=True)
        for curve in testFiles.curves:
            plt.plot(curve.x,curve.y)
        plt.savefig(figpath)
    except Exception as e:
        plt.clf()
        plt.title('Transfer Curve Error')
        plt.text(0,0.5,str(e))
        plt.savefig(figpath)
    return figpath

def checkdev(curve):
    isFailure = False
    if 'Z' in curve.info and np.mean(curve.info['Z'])>1e-7:
        isFailure = True
    tc = gTdev.transcurve(Id=curve.y,Vgs=curve.x)
    if tc.Ion.num<1e-6 or tc.Ion.num>0.001:
        isFailure = True
    if tc.OOR.num<1:
        isFailure = True
    if abs(tc.Vth.num)>3:
        isFailure = True
    if abs(tc.SS.num)>2:
        isFailure = True
    return tc,isFailure

def extractData(path):
    testKeys = ['Ion','Ioff','OOR','Vth','Gm','SS']
    attrs =[
        ["饱和电流","关态电流","开关比","阈值电压","跨导","亚阈值摆幅"],
        ['Ion','Ioff','OOR','Vth','Gm','SS'],
        ["A","A","dec","mV","mS","mV/dec"]
    ]
    ans = {}#表格数据
    for i in range(6):
        ans[testKeys[i]]= {"chsName":attrs[0][i],"engName":attrs[1][i],"Unite":attrs[2][i]}

    success = {'PMOS':[0,0],'NMOS':[0,0]}#器件有效数
    mapConfig = 'MapForStarProbe.alib.conf'
    for dtype in ['PMOS','NMOS']:
        ana_res = []#电学参数提取
        dataOut = []#热力图数据
        scount = [0 for i in range(58)]
        failOut = []#失效数据
        fcount = [0 for i in range(58)]
        subdieCount = len([None for f in os.listdir(path) if dtype in f])
        testFiles = gTdev.gtfile(location=path,key=dtype,
                Y_Axis=currentType,Z_Axis='GateI',absY=True)
        if testFiles.curves[0].name.startswith('Run0'):
            isATE=0
        else:
            isATE=1
        for curve in testFiles.curves:
            tc,isF = checkdev(curve)
            success[dtype][1] += 1
            success[dtype][0] += 0 if isF else 1
            
            p,_ = curve.name.split('@')
            p = int(p[3:])-isATE
            
            #失效器件记录
            fcount[p]+=1
            c = fcount[p]
            name = f"{dtype[0]}-Vgs-4-{58}-2-initial-{p+1}-D{p+1}{'A'+str(c) if c!=1 else ''}"            
            failOut.append([
                subdieCount if isF else 0,
                name
            ])
            if not isF:
                #有效器件记录
                scount[p]+=1
                c = scount[p]
                name = f"{dtype[0]}-Vgs-4-{58}-2-initial-{p+1}-D{p+1}{'A'+str(c) if c!=1 else ''}"
                dataOut.append([
                    tc.Ion.num,
                    tc.Ioff.num,
                    tc.OOR.num,
                    tc.Vth.num,
                    tc.Gm.num,
                    tc.SS.num,
                    name
                ])
                #电学参数提取记录
                row = [curve.name]
                row = row + [tc.Ion.num, tc.Ioff.num, tc.OOR.num]   
                row.append(tc.Vth.num*1000)
                row.append(tc.Gm.num * 1000000)
                row.append(tc.SS.num * 1000)
                ana_res.append(row)
        ana_res = pd.DataFrame(ana_res, columns=['name','Ion','Ioff','OOR','Vth','Gm','SS'])#三维数组转化为pandas.dataframe
        #电学参数提取记录
        deviceType = dtype
        for key in testKeys:
            if key in ["Ion","Ioff"]:
                try:
                    ans[key][deviceType] = '{:.2E} '.format(np.mean(np.array(ana_res[key])))
                    ans[key][deviceType] += '(±{:.1f}%)'.format(np.std(np.array(ana_res[key]),ddof=1)/np.mean(np.array(ana_res[key]))*100)
                except:
                    ans[key][deviceType] = '----'  
            elif key == 'Vth':
                try:
                    ans[key][deviceType] = '{:.2f}'.format(np.mean(np.array(ana_res[key])))
                    ans[key][deviceType] += ' ± ' + '{:.2f}'.format(np.std(np.array(ana_res[key]),ddof=1))
                except:
                    ans[key][deviceType] = '----'        
            else:
                try:
                    ans[key][deviceType] = '{:.2f}'.format(np.mean(np.array(ana_res[key])))
                    ans[key][deviceType] += ' ± ' + '{:.2f}'.format(np.std(np.array(ana_res[key]),ddof=1))  
                except:
                    ans[key][deviceType] = '----'


        #失效分析
        failcsv = os.path.join(figureDir(path),f"{dtype}Fail.csv") 
        failjpg = os.path.join(figureDir(path),f"{dtype}-Fail.jpg") 
        failOut.sort(key=lambda x:int(x[1].split('-')[6]))
        pd.DataFrame(failOut,columns=[
        'failure','name'
        ]).to_csv(failcsv)
        try:
            wuniform.drawMap(
                dataFile=failcsv,
                mapConf=mapConfig,
                valueName='failure',
                cmap='pink_r',
                file=failjpg)
        except Exception as e:
            plt.clf()
            plt.title('Fail Map Error')
            plt.text(0,0.5,str(e))
            plt.savefig(failjpg)
        #热力图分析
        datacsv = os.path.join(figureDir(path),f"{dtype}data.csv") 
        dataOut.sort(key=lambda x:int(x[6].split('-')[6]))
        pd.DataFrame(dataOut,columns=[
            'Ion','Ioff','OOR','Vth','Gm','SS','name'
        ]).to_csv(datacsv)
        for para in ['Ion','Ioff','OOR','Vth','Gm','SS']:
            try:
                wuniform.drawMap(
                    dataFile=datacsv,
                    mapConf=mapConfig,
                    valueName=para,
                    file=os.path.join(figureDir(path),f"{dtype}-{para}.jpg"))
            except Exception as e:
                plt.clf()
                plt.title(f"{dtype}-{para} Error")
                plt.text(0,0.5,str(e))
                plt.savefig(os.path.join(figureDir(path),f"{dtype}-{para}.jpg"))
    #参数表格
    columns = [
        {'name':'chsName','label':'测试项目','field':'chsName','align': 'center'},
        {'name':'engName','label':'符号','field':'engName','align': 'center'},
        {'name':'Unite','label':'单位','field':'Unite','align': 'center'},
        {'name':'PMOS','label':'PMOS','field':'PMOS','align': 'center'},
        {'name':'NMOS','label':'NMOS','field':'NMOS','align': 'center'}
    ]        
    tableInfo={"columns":columns,"data":[ans[key] for key in ans],"success":success}
    with open(os.path.join(figureDir(path),'paraTable.json'),'w',encoding='utf-8') as f:
        json.dump(tableInfo,f,ensure_ascii=False,indent=4)
    return tableInfo
def paraTable(path,force=False):
    figpath = os.path.join(figureDir(path),'paraTable.json')
    if os.path.isfile(figpath):
        if not force:
            with open(figpath,'r',encoding='utf-8') as f:
                return json.load(f)
    try:
        return extractData(path)
    except:
        return None

if __name__ == '__main__':
    print(paraTable('DataSave\\IVSweep\\2024_06_27_09_31_29'))

